package com.galaxy.user.service.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.galaxy.common.core.enums.LoginType;
import com.galaxy.common.mybatis.core.page.PageQuery;
import com.galaxy.common.mybatis.core.page.TableDataInfo;
import com.galaxy.common.satoken.utils.LoginHelper;
import com.galaxy.common.tenant.helper.TenantHelper;
import com.galaxy.system.api.model.LoginUser;
import com.galaxy.user.domain.UserAccount;
import com.galaxy.user.domain.UserBase;
import com.galaxy.user.domain.bo.UserBaseBo;
import com.galaxy.user.domain.vo.UserAccountVo;
import com.galaxy.user.domain.vo.UserBaseVo;
import com.galaxy.user.mapper.UserAccountMapper;
import com.galaxy.user.mapper.UserBaseMapper;
import com.galaxy.user.service.UserBaseService;
import io.github.linpeilie.Converter;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.security.SecureRandom;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class UserBaseServiceImpl extends ServiceImpl<UserBaseMapper, UserBase> implements UserBaseService {

    private final UserBaseMapper userBaseMapper;
    private final Converter converter;
    private final WxMaService wxMaService;

    private final UserAccountMapper userAccountMapper;

    @Override
    public TableDataInfo<UserBaseVo> queryPageList(UserBaseBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<UserBase> lqw = buildQueryWrapper(bo);
        var page = userBaseMapper.selectPage(pageQuery.build(), lqw);
        List<UserBaseVo> records = page.getRecords().stream()
            .map(userBase -> converter.convert(userBase, UserBaseVo.class))
            .collect(Collectors.toList());
        return new TableDataInfo<>(records, page.getTotal());
    }

    @Override
    public List<UserBaseVo> queryList(UserBaseBo bo) {
        LambdaQueryWrapper<UserBase> lqw = buildQueryWrapper(bo);
        return userBaseMapper.selectList(lqw).stream()
            .map(userBase -> converter.convert(userBase, UserBaseVo.class))
            .collect(Collectors.toList());
    }

    @Override
    public UserBase queryById(Long id) {
        return userBaseMapper.selectById(id);
    }

    @Override
    public String getOpenidByUserId(Long userId) {
        return userBaseMapper.selectById(userId).getOpenid();
    }

    @Override
    public Boolean insertByBo(UserBaseBo bo) {
        UserBase add = converter.convert(bo, UserBase.class);
        return userBaseMapper.insert(add) > 0;
    }

    @Override
    public Boolean updateByBo(UserBaseBo bo) {
        UserBase update = converter.convert(bo, UserBase.class);
        return userBaseMapper.updateById(update) > 0;
    }

    @Override
    public Boolean deleteWithValidByIds(List<Long> ids, Boolean isValid) {
        if (isValid) {
            // TODO: Add validation logic here
        }
        return userBaseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public UserBaseVo wxLogin(UserBase user) {
        try {
            WxMaJscode2SessionResult sessionInfo = wxMaService.getUserService().getSessionInfo(user.getCode());
            String openid = sessionInfo.getOpenid();

            LambdaQueryWrapper<UserBase> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserBase::getOpenid, openid);
            UserBaseVo one = userBaseMapper.selectVoOne(wrapper);

            if (one == null){
                //要是没有获取到就是第一次登录,就添加这个用户
                UserBase userBase = new UserBase();
                userBase.setUsername(user.getUsername());
                userBase.setAvatar("1");
                userBase.setOpenid(openid);
                // 生成用户编号
                String datePart = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                SecureRandom random = new SecureRandom();
                int randomNum = 1000 + random.nextInt(9000);
                userBase.setUserNo("U"+datePart+randomNum);
                userBaseMapper.insert(userBase);

                // 创建用户账户
                UserAccount userAccount = new UserAccount();
                userAccount.setUserId(userBase.getId());
                userAccount.setBalance(BigDecimal.valueOf(0.00));
                userAccount.setPoints(0);
                userAccount.setGender(0);
                userAccount.setLastLoginTime(LocalDateTime.now());
                userAccount.setCreateTime(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()));
                userAccount.setUpdateTime(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()));
                userAccountMapper.insert(userAccount);

                // 查询新创建的用户信息
                UserBaseVo newUser = userBaseMapper.selectVoOne(
                    new LambdaQueryWrapper<UserBase>()
                        .eq(UserBase::getOpenid, openid));

                // 设置token和用户账户信息
                newUser.setToken(token(userBase));
                newUser.setUserAccount(userAccountMapper.selectVoOne(
                    new LambdaQueryWrapper<UserAccount>()
                        .eq(UserAccount::getUserId, userBase.getId())));

                return newUser;
            }else{
                one.setToken(token(converter.convert(one, UserBase.class)));
                UserAccountVo userAccount = userAccountMapper.selectVoOne(
                    new LambdaQueryWrapper<UserAccount>()
                        .eq(UserAccount::getUserId, one.getId()));
                one.setUserAccount(userAccount);
            }
            return one;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private LambdaQueryWrapper<UserBase> buildQueryWrapper(UserBaseBo bo) {
        LambdaQueryWrapper<UserBase> lqw = Wrappers.lambdaQuery();
        lqw.eq(UserBase::getDeleted, 0);
        lqw.like(bo.getUserNo() != null, UserBase::getUserNo, bo.getUserNo());
        lqw.like(bo.getUsername() != null, UserBase::getUsername, bo.getUsername());
        lqw.like(bo.getPhone() != null, UserBase::getPhone, bo.getPhone());
        lqw.like(bo.getEmail() != null, UserBase::getEmail, bo.getEmail());
        lqw.eq(bo.getStatus() != null, UserBase::getStatus, bo.getStatus());
        return lqw;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserBase wxUpdate(UserBase userbase) {


        // 1. 更新用户基本信息
        UserBase updateUser = new UserBase();
        updateUser.setId(userbase.getId());
        updateUser.setUsername(userbase.getUsername());
        updateUser.setEmail(userbase.getEmail());
        updateUser.setPhone(userbase.getPhone());
        updateUser.setAvatar(userbase.getAvatar());
        updateUser.setUpdateTime(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()));
        userBaseMapper.updateById(updateUser);

        // 2. 更新用户账户信息
//        UserAccount updateAccount = new UserAccount();
//        updateAccount.setUserId(userbase.getId());
//        updateAccount.setGender(userbase.getGender());
//        updateAccount.setUpdateTime();
        userAccountMapper.update(new LambdaUpdateWrapper<UserAccount>()
            .set(UserAccount::getGender, userbase.getGender())
            .set(UserAccount::getUpdateTime, Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()))
            .eq(UserAccount::getUserId, userbase.getId()));

        // 3. 查询并返回更新后的完整信息
        UserBase result = userBaseMapper.selectById(userbase.getId());
        UserAccount userAccount = userAccountMapper.selectOne(
            new LambdaQueryWrapper<UserAccount>()
                .eq(UserAccount::getUserId, userbase.getId()));
        result.setUserAccount(userAccount);

        return result;
    }


    private Map<String, Object> token(UserBase user){
//        StpUtil.login(id);
        String token = StpUtil.getTokenValue();

        Map<String, Object> result = new HashMap<>();

        LoginUser loginUser = new LoginUser();
        loginUser.setUserId(user.getId());
        loginUser.setUsername(user.getUsername());
        loginUser.setNickname(user.getUsername());
        loginUser.setClientKey("app");
        loginUser.setDeviceType("android");
        loginUser.setUserType("app_user");
        loginUser.setRoleId(1L);
        SaLoginModel model = new SaLoginModel();
        model.setDevice("android");
        // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
        // 例如: 后台用户30分钟过期 app用户1天过期
        model.setTimeout(24 * 60 * 60 * 1000);
        model.setActiveTimeout(24 * 60 * 60 * 1000);
        model.setExtra(LoginHelper.CLIENT_KEY, "428a8310cd442757ae699df5d894f051");
        // 生成token
        LoginHelper.login(loginUser, model);

        result.put("token", StpUtil.getTokenValue());

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserBase updateAvatar(Long userId, String avatar) {
        // 更新用户头像信息
        UserBase updateUser = new UserBase();
        updateUser.setId(userId);
        updateUser.setAvatar(avatar);
        updateUser.setUpdateTime(Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()));
        userBaseMapper.updateById(updateUser);

        // 查询并返回更新后的用户信息
        UserBase result = userBaseMapper.selectById(userId);
        UserAccount userAccount = userAccountMapper.selectOne(
            new LambdaQueryWrapper<UserAccount>()
                .eq(UserAccount::getUserId, userId));
        result.setUserAccount(userAccount);

        return result;
    }
}
